# -*- coding: utf-8 -*-

"""
@author: Laowang
@contact: QQ:1125564921
@Created on: 2022/6/21
@Remark: 
"""

import time
import hmac
import requests
import hashlib
import json
import base64
import urllib.parse
from functools import wraps
from typing import Dict

from framework_strategy.gopy.gateways.settings import XTAPISETTING
from framework_strategy.gopy.gateways.utils import RequestParamterObj, request, ResponseEventObj


class Auth:
    """Create auth signed  """

    def __new__(cls, *args, **kwargs):
        if not hasattr(Auth, "_instance"):
            Auth._instance = object.__new__(cls)
        return Auth._instance

    def __init__(self, apiKey, secretKey):
        self._apiKey: str = apiKey
        self._secretKey: str = secretKey

    def create_payload(self, payload: dict) -> dict:
        if not all([payload.get('accesskey'), payload.get('nonce')]):
            payload['accesskey'] = self._apiKey
            payload['nonce'] = str(int(time.time() * 1000))

            # Need sorted
            params = urllib.parse.urlencode(
                dict(sorted(payload.items(), key=lambda kv: (kv[0], kv[1]))))
            signature = self._create_signed(params)

            payload['signature'] = signature
        return payload

    def _create_signed(self, params: str) -> str:
        signature = hmac.new(self._secretKey.encode(
            'utf-8'), params.encode('utf-8'), hashlib.sha256).hexdigest().upper()
        return signature


def get_auth_payload(param: dict) -> dict:
    """ return payload contains request params"""
    PUBLIC_KEY = param.pop("PUBLIC_KEY") or XTAPISETTING.PUBLIC_KEY
    SECRET_KEY = param.pop("SECRET_KEY") or XTAPISETTING.SECRET_KEY
    auth = Auth(PUBLIC_KEY, SECRET_KEY)
    return auth.create_payload(param)


# Need auth
# You can do request statistics here,
# as well as response results record
# or do stream limiting here etc
def auth_require_(this, event, parameter:RequestParamterObj):

    _, event_data = parameter.data, parameter.data.event_data
    params = get_auth_payload(event_data.kwargs)
    try:
        res = request(parameter.method, parameter.uri, params, this.proxy, exchange=event_data.exchange)
    except (requests.exceptions.HTTPError, requests.exceptions.ConnectTimeout) as err:  # NOQA
        res = False, {}, None

    res = ResponseEventObj(*res, event)
    return res


# Public
# You can do request statistics here,
# as well as response results record
# or do stream limiting here etc
def public_request_(this, event, parameter: RequestParamterObj):

    _, event_data = parameter.data, parameter.data.event_data
    params = event_data.kwargs
    try:
        res = request(parameter.method, parameter.uri, params, this.proxy, exchange=event_data.exchange)
    except (requests.exceptions.HTTPError, requests.exceptions.ConnectTimeout) as err:  # NOQA
        res = False, {}, None
    res = ResponseEventObj(*res, event)
    return res


# Request carrier parameter checkup
def sign_encrypt_data(data: Dict) -> str:
    """ Used to process request parameters and convert them into the encrypted 
    signature required by the request  """
    order_lines = json.dumps(data)
    order_lines = base64.b64encode(order_lines.encode('utf-8'))
    base64_data = str(order_lines, 'utf-8')
    return base64_data



